return 0;
}
+
+int flask_add_pirq(int xc_handle, unsigned int pirq, char *scontext)
+{
+ int err;
+ flask_op_t op;
+ char *buf;
+ char *pirq_s = OCON_PIRQ_STR;
+ int size = INITCONTEXTLEN + strlen(pirq_s) + (sizeof(unsigned int)) +
+ (sizeof(char) * 3);
+
+ if ( (buf = (char *) malloc(size)) == NULL )
+ return -ENOMEM;
+ memset(buf, 0, size);
+
+ op.cmd = FLASK_ADD_OCONTEXT;
+ snprintf(buf, size, "%s %255s %u", pirq_s, scontext, pirq);
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+ {
+ free(buf);
+ return err;
+ }
+
+ free(buf);
+ return 0;
+
+}
+
+int flask_add_ioport(int xc_handle, unsigned long low, unsigned long high,
+ char *scontext)
+{
+ int err;
+ flask_op_t op;
+ char *buf;
+ char *ioport = OCON_IOPORT_STR;
+ int size = INITCONTEXTLEN + strlen(ioport) +
+ (sizeof(unsigned long) * 2) + (sizeof(char) * 4);
+
+ if ( (buf = (char *) malloc(size)) == NULL )
+ return -ENOMEM;
+ memset(buf, 0, size);
+
+ op.cmd = FLASK_ADD_OCONTEXT;
+ snprintf(buf, size, "%s %255s %li %li", ioport, scontext, low, high);
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+ {
+ free(buf);
+ return err;
+ }
+
+ free(buf);
+ return 0;
+
+}
+
+int flask_add_iomem(int xc_handle, unsigned long low, unsigned long high,
+ char *scontext)
+{
+ int err;
+ flask_op_t op;
+ char *buf;
+ char *iomem = OCON_IOMEM_STR;
+ int size = INITCONTEXTLEN + strlen(iomem) +
+ (sizeof(unsigned long) * 2) + (sizeof(char) * 4);
+
+ if ( (buf = (char *) malloc(size)) == NULL )
+ return -ENOMEM;
+ memset(buf, 0, size);
+
+ op.cmd = FLASK_ADD_OCONTEXT;
+ snprintf(buf, size, "%s %255s %li %li", iomem, scontext, low, high);
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+ {
+ free(buf);
+ return err;
+ }
+
+ free(buf);
+ return 0;
+
+}
+
+int flask_add_device(int xc_handle, unsigned long device, char *scontext)
+{
+ int err;
+ flask_op_t op;
+ char *buf;
+ char *dev = OCON_DEVICE_STR;
+ int size = INITCONTEXTLEN + strlen(dev) + (sizeof(unsigned long)) +
+ (sizeof(char) * 3);
+
+ if ( (buf = (char *) malloc(size)) == NULL )
+ return -ENOMEM;
+ memset(buf, 0, size);
+
+ op.cmd = FLASK_ADD_OCONTEXT;
+ snprintf(buf, size, "%s %255s %li", dev, scontext, device);
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+ {
+ free(buf);
+ return err;
+ }
+
+ free(buf);
+ return 0;
+
+}
+
+int flask_del_pirq(int xc_handle, unsigned int pirq)
+{
+ int err;
+ flask_op_t op;
+ char *buf;
+ char *pirq_s = OCON_PIRQ_STR;
+ int size = strlen(pirq_s) + (sizeof(unsigned int)) +
+ (sizeof(char) * 2);
+
+ if ( (buf = (char *) malloc(size)) == NULL )
+ return -ENOMEM;
+ memset(buf, 0, size);
+
+ op.cmd = FLASK_DEL_OCONTEXT;
+ snprintf(buf, size, "%s %u", pirq_s, pirq);
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+ {
+ free(buf);
+ return err;
+ }
+
+ free(buf);
+ return 0;
+
+}
+
+int flask_del_ioport(int xc_handle, unsigned long low, unsigned long high)
+{
+ int err;
+ flask_op_t op;
+ char *buf;
+ char *ioport = OCON_IOPORT_STR;
+ int size = strlen(ioport) + (sizeof(unsigned long) * 2) +
+ (sizeof(char) * 3);
+
+ if ( (buf = (char *) malloc(size)) == NULL )
+ return -ENOMEM;
+ memset(buf, 0, size);
+
+ op.cmd = FLASK_DEL_OCONTEXT;
+ snprintf(buf, size, "%s %li %li", ioport, low, high);
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+ {
+ free(buf);
+ return err;
+ }
+
+ free(buf);
+ return 0;
+
+}
+
+int flask_del_iomem(int xc_handle, unsigned long low, unsigned long high)
+{
+ int err;
+ flask_op_t op;
+ char *buf;
+ char *iomem = OCON_IOMEM_STR;
+ int size = strlen(iomem) + (sizeof(unsigned long) * 2) +
+ (sizeof(char) * 3);
+
+ if ( (buf = (char *) malloc(size)) == NULL )
+ return -ENOMEM;
+ memset(buf, 0, size);
+
+ op.cmd = FLASK_DEL_OCONTEXT;
+ snprintf(buf, size, "%s %li %li", iomem, low, high);
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+ {
+ free(buf);
+ return err;
+ }
+
+ free(buf);
+ return 0;
+
+}
+
+int flask_del_device(int xc_handle, unsigned long device)
+{
+ int err;
+ flask_op_t op;
+ char *buf;
+ char *dev = OCON_DEVICE_STR;
+ int size = strlen(dev) + (sizeof(unsigned long)) + (sizeof(char) * 2);
+
+ if ( (buf = (char *) malloc(size)) == NULL )
+ return -ENOMEM;
+ memset(buf, 0, size);
+
+ op.cmd = FLASK_DEL_OCONTEXT;
+ snprintf(buf, size, "%s %li", dev, device);
+ op.buf = buf;
+ op.size = size;
+
+ if ( (err = xc_flask_op(xc_handle, &op)) != 0 )
+ {
+ free(buf);
+ return err;
+ }
+
+ free(buf);
+ return 0;
+
+}
int flask_sid_to_context(int xc_handle, int sid, char *buf, uint32_t size);
int flask_getenforce(int xc_handle);
int flask_setenforce(int xc_handle, int mode);
+int flask_add_pirq(int xc_handle, unsigned int pirq, char *scontext);
+int flask_add_ioport(int xc_handle, unsigned long low, unsigned long high,
+ char *scontext);
+int flask_add_iomem(int xc_handle, unsigned long low, unsigned long high,
+ char *scontext);
+int flask_add_device(int xc_handle, unsigned long device, char *scontext);
+int flask_del_pirq(int xc_handle, unsigned int pirq);
+int flask_del_ioport(int xc_handle, unsigned long low, unsigned long high);
+int flask_del_iomem(int xc_handle, unsigned long low, unsigned long high);
+int flask_del_device(int xc_handle, unsigned long device);
+#define flask_add_single_ioport(x, l, s) flask_add_ioport(x, l, l, s)
+#define flask_add_single_iomem(x, l, s) flask_add_iomem(x, l, l, s)
+#define flask_del_single_ioport(x, l) flask_del_ioport(x, l, l)
+#define flask_del_single_iomem(x, l) flask_del_iomem(x, l, l);
+#define OCON_PIRQ_STR "pirq"
+#define OCON_IOPORT_STR "ioport"
+#define OCON_IOMEM_STR "iomem"
+#define OCON_DEVICE_STR "pcidevice"
+#define INITCONTEXTLEN 256
#endif /* __FLASK_H__ */
setenforce
setbool
setsecparam
+ add_ocontext
+ del_ocontext
}
allow dom0_t security_t:security {compute_av compute_create compute_member
check_context load_policy compute_relabel compute_user setenforce setbool
-setsecparam};
+setsecparam add_ocontext del_ocontext};
create_channel(dom0_t, dom0_t, evchn0-0_t)
allow dom0_t evchn0-0_t:event {send};
#define FLASK_AVC_HASHSTATS 18
#define FLASK_AVC_CACHESTATS 19
#define FLASK_MEMBER 20
+#define FLASK_ADD_OCONTEXT 21
+#define FLASK_DEL_OCONTEXT 22
-#define FLASK_LAST FLASK_MEMBER
+#define FLASK_LAST FLASK_DEL_OCONTEXT
typedef struct flask_op {
uint32_t cmd;
1UL<<FLASK_COMMITBOOLS | \
1UL<<FLASK_DISABLE | \
1UL<<FLASK_SETAVC_THRESHOLD | \
- 1UL<<FLASK_MEMBER \
+ 1UL<<FLASK_MEMBER | \
+ 1UL<<FLASK_ADD_OCONTEXT | \
+ 1UL<<FLASK_DEL_OCONTEXT \
)
#define FLASK_COPY_OUT \
return length;
}
+static int flask_ocontext_del(char *buf, uint32_t size)
+{
+ int len = 0;
+ char *ocontext;
+ unsigned long low = 0;
+ unsigned long high = 0;
+
+ len = domain_has_security(current->domain, SECURITY__DEL_OCONTEXT);
+ if ( len )
+ return len;
+
+ if ( (ocontext = xmalloc_bytes(size) ) == NULL )
+ return -ENOMEM;
+
+ len = sscanf(buf, "%s %li %li", ocontext, &low, &high);
+ if ( len < 2 )
+ {
+ len = -EINVAL;
+ goto out;
+ }
+ else if ( len == 2 )
+ high = low;
+
+ if ( low > high )
+ {
+ len = -EINVAL;
+ goto out;
+ }
+
+ len = security_ocontext_del(ocontext, low, high);
+ out:
+ xfree(ocontext);
+ return len;
+}
+
+static int flask_ocontext_add(char *buf, uint32_t size)
+{
+ int len = 0;
+ u32 sid = 0;
+ unsigned long low = 0;
+ unsigned long high = 0;
+ char *scontext;
+ char *ocontext;
+
+ len = domain_has_security(current->domain, SECURITY__ADD_OCONTEXT);
+ if ( len )
+ return len;
+
+ if ( (scontext = xmalloc_bytes(size) ) == NULL )
+ return -ENOMEM;
+
+ if ( (ocontext = xmalloc_bytes(size) ) == NULL )
+ {
+ xfree(scontext);
+ return -ENOMEM;
+ }
+
+ memset(scontext, 0, size);
+ memset(ocontext, 0, size);
+
+ len = sscanf(buf, "%s %s %li %li", ocontext, scontext, &low, &high);
+ if ( len < 3 )
+ {
+ len = -EINVAL;
+ goto out;
+ }
+ else if ( len == 3 )
+ high = low;
+
+ if ( low > high )
+ {
+ len = -EINVAL;
+ goto out;
+ }
+ len = security_context_to_sid(scontext, strlen(scontext)+1, &sid);
+ if ( len < 0 )
+ {
+ len = -EINVAL;
+ goto out;
+ }
+ len = security_ocontext_add(ocontext, low, high, sid);
+out:
+ xfree(ocontext);
+ xfree(scontext);
+ return len;
+}
+
long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_op)
{
flask_op_t curop, *op = &curop;
}
break;
+ case FLASK_ADD_OCONTEXT:
+ {
+ length = flask_ocontext_add(arg, op->size);
+ break;
+ }
+
+ case FLASK_DEL_OCONTEXT:
+ {
+ length = flask_ocontext_del(arg, op->size);
+ break;
+ }
+
default:
length = -ENOSYS;
break;
S_(SECCLASS_SECURITY, SECURITY__SETENFORCE, "setenforce")
S_(SECCLASS_SECURITY, SECURITY__SETBOOL, "setbool")
S_(SECCLASS_SECURITY, SECURITY__SETSECPARAM, "setsecparam")
+ S_(SECCLASS_SECURITY, SECURITY__ADD_OCONTEXT, "add_ocontext")
+ S_(SECCLASS_SECURITY, SECURITY__DEL_OCONTEXT, "del_ocontext")
#define SECURITY__SETENFORCE 0x00000080UL
#define SECURITY__SETBOOL 0x00000100UL
#define SECURITY__SETSECPARAM 0x00000200UL
+#define SECURITY__ADD_OCONTEXT 0x00000400UL
+#define SECURITY__DEL_OCONTEXT 0x00000800UL
int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass);
+int security_ocontext_add(char *ocontext, unsigned long low,
+ unsigned long high, u32 sid);
+
+int security_ocontext_del(char *ocontext, unsigned int low, unsigned int high);
#endif /* _FLASK_SECURITY_H_ */
xfree(bvalues);
return rc;
}
+
+int determine_ocontext( char *ocontext )
+{
+ if ( strcmp(ocontext, "pirq") == 0 )
+ return OCON_PIRQ;
+ else if ( strcmp(ocontext, "ioport") == 0 )
+ return OCON_IOPORT;
+ else if ( strcmp(ocontext, "iomem") == 0 )
+ return OCON_IOMEM;
+ else if ( strcmp(ocontext, "pcidevice") == 0 )
+ return OCON_DEVICE;
+ else
+ return -1;
+}
+
+int security_ocontext_add( char *ocontext, unsigned long low, unsigned long high
+ ,u32 sid )
+{
+ int ret = 0;
+ int ocon = 0;
+ struct ocontext *c;
+ struct ocontext *add;
+
+ if ( (ocon = determine_ocontext(ocontext)) < 0 )
+ return -EINVAL;
+ if ( (add = xmalloc(struct ocontext)) == NULL )
+ return -ENOMEM;
+ memset(add, 0, sizeof(struct ocontext));
+ add->sid[0] = sid;
+
+ POLICY_WRLOCK;
+ switch( ocon )
+ {
+ case OCON_PIRQ:
+ add->u.pirq = (u16)low;
+ if ( high != low )
+ {
+ ret = -EINVAL;
+ break;
+ }
+
+ c = policydb.ocontexts[OCON_PIRQ];
+ while ( c )
+ {
+ if ( c->u.pirq == add->u.pirq )
+ {
+ printk("%s: Duplicate pirq %d\n", __FUNCTION__, add->u.pirq);
+ ret = -EINVAL;
+ break;
+ }
+ c = c->next;
+ }
+
+ if ( ret == 0 )
+ {
+ add->next = policydb.ocontexts[OCON_PIRQ];
+ policydb.ocontexts[OCON_PIRQ] = add;
+ }
+ break;
+
+ case OCON_IOPORT:
+ add->u.ioport.low_ioport = low;
+ add->u.ioport.high_ioport = high;
+
+ c = policydb.ocontexts[OCON_IOPORT];
+ while ( c )
+ {
+ if ( c->u.ioport.low_ioport <= add->u.ioport.high_ioport &&
+ add->u.ioport.low_ioport <= c->u.ioport.high_ioport )
+ {
+ printk("%s: IO Port overlap with entry 0x%x - 0x%x\n",
+ __FUNCTION__, c->u.ioport.low_ioport,
+ c->u.ioport.high_ioport);
+ ret = -EINVAL;
+ break;
+ }
+ c = c->next;
+ }
+
+ if ( ret == 0 )
+ {
+ add->next = policydb.ocontexts[OCON_IOPORT];
+ policydb.ocontexts[OCON_IOPORT] = add;
+ }
+ break;
+
+ case OCON_IOMEM:
+ add->u.iomem.low_iomem = low;
+ add->u.iomem.high_iomem = high;
+
+ c = policydb.ocontexts[OCON_IOMEM];
+ while ( c )
+ {
+ if ( c->u.iomem.low_iomem <= add->u.iomem.high_iomem &&
+ add->u.iomem.low_iomem <= c->u.iomem.high_iomem )
+ {
+ printk("%s: IO Memory overlap with entry 0x%x - 0x%x\n",
+ __FUNCTION__, c->u.iomem.low_iomem,
+ c->u.iomem.high_iomem);
+ ret = -EINVAL;
+ break;
+ }
+ c = c->next;
+ }
+
+ if ( ret == 0 )
+ {
+ add->next = policydb.ocontexts[OCON_IOMEM];
+ policydb.ocontexts[OCON_IOMEM] = add;
+ }
+ break;
+
+ case OCON_DEVICE:
+ add->u.device = low;
+ if ( high != low )
+ {
+ ret = -EINVAL;
+ break;
+ }
+
+ c = policydb.ocontexts[OCON_DEVICE];
+ while ( c )
+ {
+ if ( c->u.device == add->u.device )
+ {
+ printk("%s: Duplicate PCI Device 0x%x\n", __FUNCTION__,
+ add->u.device);
+ ret = -EINVAL;
+ break;
+ }
+ c = c->next;
+ }
+
+ if ( ret == 0 )
+ {
+ add->next = policydb.ocontexts[OCON_DEVICE];
+ policydb.ocontexts[OCON_DEVICE] = add;
+ }
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+ POLICY_WRUNLOCK;
+
+ if ( ret != 0 )
+ xfree(add);
+ return ret;
+}
+
+int security_ocontext_del( char *ocontext, unsigned int low, unsigned int high )
+{
+ int ret = 0;
+ int ocon = 0;
+ struct ocontext *c, *before_c;
+
+ if ( (ocon = determine_ocontext(ocontext)) < 0 )
+ return -EINVAL;
+
+ POLICY_WRLOCK;
+ switch( ocon )
+ {
+ case OCON_PIRQ:
+ for ( before_c = NULL, c = policydb.ocontexts[OCON_PIRQ];
+ c; before_c = c, c = c->next )
+ {
+ if ( c->u.pirq == low )
+ {
+ if ( before_c == NULL )
+ {
+ policydb.ocontexts[OCON_PIRQ] = c->next;
+ xfree(c);
+ goto out;
+ }
+ else
+ {
+ before_c->next = c->next;
+ xfree(c);
+ goto out;
+ }
+ }
+ }
+
+ printk("%s: ocontext not found: pirq %d\n", __FUNCTION__, low);
+ ret = -EINVAL;
+ break;
+
+ case OCON_IOPORT:
+ for ( before_c = NULL, c = policydb.ocontexts[OCON_IOPORT];
+ c; before_c = c, c = c->next )
+ {
+ if ( c->u.ioport.low_ioport == low &&
+ c->u.ioport.high_ioport == high )
+ {
+ if ( before_c == NULL )
+ {
+ policydb.ocontexts[OCON_IOPORT] = c->next;
+ xfree(c);
+ goto out;
+ }
+ else
+ {
+ before_c->next = c->next;
+ xfree(c);
+ goto out;
+ }
+ }
+ }
+
+ printk("%s: ocontext not found: ioport 0x%x - 0x%x\n", __FUNCTION__,
+ low, high);
+ ret = -EINVAL;
+ break;
+
+ case OCON_IOMEM:
+ for ( before_c = NULL, c = policydb.ocontexts[OCON_IOMEM];
+ c; before_c = c, c = c->next )
+ {
+ if ( c->u.iomem.low_iomem == low &&
+ c->u.iomem.high_iomem == high )
+ {
+ if ( before_c == NULL )
+ {
+ policydb.ocontexts[OCON_IOMEM] = c->next;
+ xfree(c);
+ goto out;
+ }
+ else
+ {
+ before_c->next = c->next;
+ xfree(c);
+ goto out;
+ }
+ }
+ }
+
+ printk("%s: ocontext not found: iomem 0x%x - 0x%x\n", __FUNCTION__,
+ low, high);
+ ret = -EINVAL;
+ break;
+
+ case OCON_DEVICE:
+ for ( before_c = NULL, c = policydb.ocontexts[OCON_DEVICE];
+ c; before_c = c, c = c->next )
+ {
+ if ( c->u.device == low )
+ {
+ if ( before_c == NULL )
+ {
+ policydb.ocontexts[OCON_DEVICE] = c->next;
+ xfree(c);
+ goto out;
+ }
+ else
+ {
+ before_c->next = c->next;
+ xfree(c);
+ goto out;
+ }
+ }
+ }
+
+ printk("%s: ocontext not found: pcidevice 0x%x\n", __FUNCTION__, low);
+ ret = -EINVAL;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ out:
+ POLICY_WRUNLOCK;
+ return ret;
+}